#include "ASMInstruction.hpp"
#include "CodeGen.hpp"
#include "Module.hpp"

#include <iostream>
#include <memory>
#include <unordered_map>

void declare_global(CodeGen *codegen); // 声明全局变量 a
void translate_main(CodeGen *codegen); // 将 main 函数翻译为汇编代码

int main() {
    auto *module = new Module();
    auto *codegen = new CodeGen(module);

    // 告诉汇编器将汇编放到代码段
    codegen->append_inst(".text", ASMInstruction::Atrribute);

    declare_global(codegen);

    codegen->append_inst(".text", ASMInstruction::Atrribute);
    translate_main(codegen);

    std::cout << codegen->print();
    delete codegen;
    delete module;
    return 0;
}

void declare_global(CodeGen *codegen) {
    // 声明全局变量 a
    // 将 a 放到 .data 段中
    codegen->append_inst(".data",ASMInstruction::Atrribute);
    // 标记 a 为全局变量
    codegen->append_inst(".globl a", ASMInstruction::Atrribute);
    // 标记 a 为数据对象 (变量)
    codegen->append_inst(".type a, @object", ASMInstruction::Atrribute);
    // 标记 a 的大小为 4 字节
    codegen->append_inst(".size a, 4", ASMInstruction::Atrribute);
    // a 的标签
    codegen->append_inst("a", ASMInstruction::Label);
    // 分配 4 字节未初始化空间
    codegen->append_inst(".zero 4");
}

// TODO: 按照自己的理解翻译main函数，可以按照注释中的步骤，也可自由发挥
// 提示：可以使用 la t0, a  指令将全局变量a的内存地址放到t0寄存器中
void translate_main(CodeGen *codegen) {
    // 声明 main 函数
    codegen->append_inst(ASMInstruction(".globl main", ASMInstruction::Atrribute));
    codegen->append_inst(ASMInstruction(".type main, @function", ASMInstruction::Atrribute));

    // main 函数开始
    codegen->append_inst(ASMInstruction("main", ASMInstruction::Label));

    // main 函数的 Prologue (序言)
    codegen->append_inst(ASMInstruction("addi sp, sp, -8", ASMInstruction::Instruction));
    codegen->append_inst(ASMInstruction("sw ra, 0(sp)", ASMInstruction::Instruction));

    // main 函数的 label_entry
    codegen->append_inst(ASMInstruction("label_entry", ASMInstruction::Label));

    // store i32 10, i32* @a
    codegen->append_inst(ASMInstruction("la t0, a", ASMInstruction::Instruction));
    codegen->append_inst(ASMInstruction("li t1, 10", ASMInstruction::Instruction));
    codegen->append_inst(ASMInstruction("sw t1, 0(t0)", ASMInstruction::Instruction));

    // %op0 = load i32, i32* @a
    codegen->append_inst(ASMInstruction("la t0, a", ASMInstruction::Instruction));
    codegen->append_inst(ASMInstruction("lw t1, 0(t0)", ASMInstruction::Instruction));

    // ret i32 %op0
    codegen->append_inst(ASMInstruction("mv a0, t1", ASMInstruction::Instruction));

    // main 函数的 Epilogue (收尾)
    codegen->append_inst(ASMInstruction("lw ra, 0(sp)", ASMInstruction::Instruction));
    codegen->append_inst(ASMInstruction("addi sp, sp, 8", ASMInstruction::Instruction));
    codegen->append_inst(ASMInstruction("jr ra", ASMInstruction::Instruction));
}